package com.tanhua.dubbo.server.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.dubbo.config.annotation.Service;
import com.tanhua.dubbo.server.pojo.UserLike;
import com.tanhua.dubbo.server.vo.PageInfo;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Service(version = "1.0.0")
public class UserLikeApiImpl implements UserLikeApi {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public static final String LIKE_REDIS_KEY_PREFIX = "USER_LIKE_";

    public static final String NOT_LIKE_REDIS_KEY_PREFIX = "USER_NOT_LIKE_";

    //redis缓存中的喜欢前缀
    public String getLikeRedisKeyPrefix(Long userId) {
        return LIKE_REDIS_KEY_PREFIX + userId;
    }

    //redis缓存中的不喜欢前缀
    public String getNotLikeRedisKeyPrefix(Long userId) {
        return NOT_LIKE_REDIS_KEY_PREFIX + userId;
    }


    /**
     * 喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean likeUser(Long userId, Long likeUserId) {
        //判断用户是否喜欢
        if (this.isLike(userId, likeUserId)) {
            return false;
        }
        //如果用户还未喜欢,或者不喜欢
        //创建喜欢的类的对象
        UserLike userLike = new UserLike();
        userLike.setCreated(System.currentTimeMillis());
        userLike.setUserId(userId);
        userLike.setLikeUserId(likeUserId);
        userLike.setId(ObjectId.get());
        //保存喜欢数据到MongoDB中去
        this.mongoTemplate.save(userLike);
        //写入redis缓存中,喜欢列表中
        String redisKey = getLikeRedisKeyPrefix(userId);
        String hashKey = String.valueOf(likeUserId);
        redisTemplate.opsForHash().put(redisKey, hashKey, "1");
        //将不喜欢的列表数据删除
        if (this.isNotLike(userId, likeUserId)) {
            redisKey = getNotLikeRedisKeyPrefix(userId);
            redisTemplate.opsForHash().delete(redisKey, hashKey);
        }
        return true;
    }

    /**
     * 判断用户是否喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    public boolean isLike(Long userId, Long likeUserId) {
        return redisTemplate.opsForHash().hasKey(getLikeRedisKeyPrefix(userId), String.valueOf(likeUserId));
    }

    /**
     * 判断用户是否不喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    public boolean isNotLike(Long userId, Long likeUserId) {
        return redisTemplate.opsForHash().hasKey(getNotLikeRedisKeyPrefix(userId), String.valueOf(likeUserId));
    }

    /**
     * 不喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean notLikeUser(Long userId, Long likeUserId) {
        //确定用户是否不喜欢
        if (this.isNotLike(userId, likeUserId)) {
            return false;
        }
        //将不喜欢保存到redis缓存中去
        String redisKey = getNotLikeRedisKeyPrefix(userId);
        String hashKey = String.valueOf(likeUserId);
        redisTemplate.opsForHash().put(redisKey, hashKey, "1");
        //将MongoDB中的喜欢数据删除掉就行
        if (isLike(userId, likeUserId)) {
            Query query = Query.query(Criteria.where("userId").is(userId).and("likeUserId").is(likeUserId));
            this.mongoTemplate.remove(query, UserLike.class);
            redisKey = this.getLikeRedisKeyPrefix(userId);
            this.redisTemplate.opsForHash().delete(redisKey, hashKey);
        }
        return true;
    }

    /**
     * 是否相互喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean isMutualLike(Long userId, Long likeUserId) {
        return this.isLike(userId, likeUserId)
                && this.isLike(likeUserId, userId);
    }

    /**
     * 查询喜欢列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<Long> queryLikeList(Long userId) {
        String redisKey = this.getLikeRedisKeyPrefix(userId);
        Set<Object> keys = this.redisTemplate.opsForHash().keys(redisKey);
        if (CollUtil.isEmpty(keys)) {
            return ListUtil.empty();
        }
        List<Long> result = new ArrayList<>(keys.size());
        keys.forEach(o -> result.add(Convert.toLong(o)));
        return result;
    }

    /**
     * 查询不喜欢列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<Long> queryNotLikeList(Long userId) {
        String redisKey = this.getNotLikeRedisKeyPrefix(userId);
        Set<Object> keys = this.redisTemplate.opsForHash().keys(redisKey);
        if (CollUtil.isEmpty(keys)) {
            return ListUtil.empty();
        }

        List<Long> result = new ArrayList<>(keys.size());
        keys.forEach(o -> result.add(Convert.toLong(o)));
        return result;
    }

    /**
     * 相互喜欢的数量
     *
     * @param userId
     * @return
     */
    @Override
    public Long queryMutualLikeCount(Long userId) {
        try {
            List<Long> likeIds = this.queryLikeList(userId);
            Long eachLoveCounts = Convert.toLong(0);
            for (Long likeId : likeIds) {
                boolean like = isLike(likeId, userId);
                eachLoveCounts++;
            }
            return eachLoveCounts;
        } catch (Exception e) {
            return Convert.toLong(0);
        }
    }

    /**
     * 喜欢数
     *
     * @param userId
     * @return
     */
    @Override
    public Long queryLikeCount(Long userId) {
        return Convert.toLong(this.queryLikeList(userId).size());
    }

    /**
     * 粉丝数
     *
     * @param userId
     * @return
     */
    @Override
    public Long queryFanCount(Long userId) {
        try {
            //从MongoDB中查询
            Query query = Query.query(Criteria.where("likeUserId").is(userId));
            long count = this.mongoTemplate.count(query, UserLike.class);
            return count;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 查询相互喜欢列表
     *
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<UserLike> queryMutualLikeList(Long userId, Integer page, Integer pageSize) {
        List<Long> longs = this.queryLikeList(userId);
        Query query = Query.query(Criteria.where("userId").in(longs).and("likeUserId").is(userId));
        return this.queryList(query, page, pageSize);
    }

    /**
     * 根据条件查询喜欢用户
     *
     * @param query
     * @param page
     * @param pageSize
     * @return
     */
    private PageInfo<UserLike> queryList(Query query, Integer page, Integer pageSize) {
        PageInfo<UserLike> pageInfo = new PageInfo<>();
        pageInfo.setPageSize(pageSize);
        pageInfo.setPageNum(page);
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
        query.with(pageRequest);
        List<UserLike> userLikes = mongoTemplate.find(query, UserLike.class);
        pageInfo.setRecords(userLikes);
        return pageInfo;
    }

    /**
     * 查询我喜欢的列表
     *
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<UserLike> queryLikeList(Long userId, Integer page, Integer pageSize) {
        List<Long> longs = this.queryLikeList(userId);
        Query query = Query.query(Criteria.where("userId").is(userId).and("likeUserId").in(longs));
        return this.queryList(query, page, pageSize);
    }

    /**
     * 查询粉丝列表
     *
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<UserLike> queryFanList(Long userId, Integer page, Integer pageSize) {
        Query query = Query.query(Criteria.where("likeUserId").is(userId));
        return this.queryList(query, page, pageSize);
    }


}
